package org.ucas.faker.web.fetcher.parse;

import org.ucas.faker.web.fetcher.cond.FetchCond;
import org.ucas.faker.web.fetcher.meta.ColumnField;
import org.ucas.faker.web.fetcher.meta.CondTable;
import org.ucas.faker.web.fetcher.meta.Table;
import org.ucas.faker.web.service.Visualization.json.CloneUtil;
import org.ucas.faker.web.utils.CloneUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TableMeta implements Serializable {

  List<Table> tables = new ArrayList<>();

  Map<String,ColumnField> fields = new HashMap<>();

  JoinGraph graph = new JoinGraph();

  public ColumnField column(String name) {

    if("*".equals(name)) return ColumnField.ANY;

    ColumnField res = fields.getOrDefault(name,null);

    if(res != null) return res;

    if(name.indexOf(".") != -1) {
      String prefix = name.split("\\.")[0];
      name = name.split("\\.")[1];
      Table dst = null;
      for(Table table:tables) {
        if(prefix.equals(table.name) || (table.clazz != null && table.clazz.getSimpleName().equals(prefix))) {
          prefix = table.name;
          dst = table;
          break;
        }
      }
      res = fields.getOrDefault(prefix + "." + name,null);

      if(res == null) {
        res = new ColumnField(name);
        res.table = dst == null? new Table(prefix) : dst;
      }
    } else {
      for(Table table:tables) {
        String key = table.name + "." + name;
        res = fields.getOrDefault(key,null);
        if(res!=null) break;
      }
      if(res == null) res = new ColumnField(name);
    }
    return res;
  }

  public Table table(String name) {
    for(Table table:tables)
      if(table.name.equals(name) || (table.clazz != null && table.clazz.getSimpleName().equals(name))) return table;
    return new Table(name);
  }

  public void add(ColumnField column) {
    fields.put(column.alias,column);
    Table table = column.table;
    if(table != null && table instanceof CondTable) {
      add((CondTable) column.table);
    }
  }

  public void add(String key, ColumnField field, FetchCond cond) {
    ColumnField dst = CloneUtils.clone(field);
    dst.alias = key;
    String tableName = field.table == null? "table_"+key : field.table.name +"_" + key;
    Table table = new CondTable(tableName,field.table,cond);
    dst.table = table;
    add(dst);
  }

  public void add(CondTable table) {
    if(graph.data.containsKey(table)) return;
    List<JoinGraph.JoinEdge> edges = new ArrayList<>();
    for(JoinGraph.JoinEdge edge:graph.edges(table.original)) {
      JoinGraph.JoinEdge tmp = CloneUtils.clone(edge);
      if(tmp == null) continue;
      tmp.join.replace(table.original,table);
      edges.add(tmp);
    }
    graph.data.put(table,edges);
  }

  public JoinGraph graph() {
    return graph;
  }
}
